#include <iostream>
#include <stdexcept>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <memory>
#include <algorithm>
#include <cstdint>
#include <vulkan/vulkan.hpp>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_raii.hpp>
#include <vulkan/vulkan_structs.hpp>
#include <vulkan/vk_platform.h>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

constexpr uint32_t WIDTH = 800;
constexpr uint32_t HEIGHT = 600;

const std::vector<char const *> validationLayers = {
    "VK_LAYER_KHRONOS_validation"};

#ifdef NDEBUG
constexpr bool enableValidationLayers = false;
#else
constexpr bool enableValidationLayers = true;
#endif

class HelloTriangleApplication
{
public:
    void run()
    {
        initWindow();
        initVulkan();
        mainLoop();
        cleanup();
    }

private:
    GLFWwindow *window = nullptr;

    vk::raii::Context context;
    vk::raii::Instance instance = nullptr;
    vk::raii::DebugUtilsMessengerEXT debugMessenger = nullptr;
    vk::raii::PhysicalDevice physicalDevice = nullptr;
    vk::raii::Device device = nullptr;
    vk::raii::Queue graphicsQueue = nullptr;

    vk::raii::SurfaceKHR surface = nullptr;

    std::vector<const char*> requiredDeviceExtension = {
        // 交换链扩展
        vk::KHRSwapchainExtensionName,
        // SPIR-V 1.4 扩展
        vk::KHRSpirv14ExtensionName,
        // 同步2扩展
        vk::KHRSynchronization2ExtensionName,
        // 创建渲染通道2扩展
        vk::KHRCreateRenderpass2ExtensionName
    };

    void initWindow()
    {
        glfwInit();

        glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
        glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

        window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
    }

    void initVulkan()
    {
        createInstance();
        // 注释掉setupDebugMessenger()调用，因为调试信使已经在实例创建时通过pNext链激活
        // setupDebugMessenger();
        createSurface();
        pickPhysicalDevice();
        createLogicalDevice();
    }

    void mainLoop()
    {
        while (!glfwWindowShouldClose(window))
        {
            glfwPollEvents();
        }
    }

    void cleanup()
    {
        glfwDestroyWindow(window);
        glfwTerminate();
    }

    void createInstance()
    {
        constexpr vk::ApplicationInfo appInfo(
            "Hello Triangle",
            VK_MAKE_VERSION(1, 0, 0),
            "No Engine",
            VK_MAKE_VERSION(1, 0, 0),
            vk::ApiVersion14);

        // Get the required layers
        std::vector<char const *> requiredLayers;
        if (enableValidationLayers)
        {
            requiredLayers.assign(validationLayers.begin(), validationLayers.end());
        }

        // Check if the required layers are supported by the Vulkan implementation.
        auto layerProperties = context.enumerateInstanceLayerProperties();
        for (auto const &requiredLayer : requiredLayers)
        {
            // 打印验证的layer
            std::cout << "Checking layer: " << requiredLayer << std::endl;
            // 使用 C++20 的 std::ranges::none_of 算法
            // 检查 layerProperties 容器中是否没有任何元素满足 lambda 表达式的条件
            // lambda 表达式比较层属性中的 layerName 与 requiredLayer 是否相等
            // 使用 strcmp 进行字符串比较
            if (std::ranges::none_of(layerProperties,
                                     [requiredLayer](auto const &layerProperty)
                                     { return strcmp(layerProperty.layerName, requiredLayer) == 0; }))
            {
                throw std::runtime_error("Required layer not supported: " + std::string(requiredLayer));
            }
        }

        // Get the required extensions.
        auto requiredExtensions = getRequiredExtensions();
#ifdef __APPLE__
        requiredExtensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
        // Check if the required extensions are supported by the Vulkan implementation.
        auto extensionProperties = context.enumerateInstanceExtensionProperties();

        for (auto const &requiredExtension : requiredExtensions)
        {
            // 打印验证的extension
            std::cout << "Checking extension: " << requiredExtension << std::endl;
            if (std::ranges::none_of(extensionProperties,
                                     [requiredExtension](auto const &extensionProperty)
                                     {
                                         return strcmp(extensionProperty.extensionName, requiredExtension) == 0;
                                     }))
            {
                throw std::runtime_error("Required extension not supported: " + std::string(requiredExtension));
            }
        }

        // 配置调试信使创建信息，在实例创建时就激活调试回调
        vk::DebugUtilsMessengerCreateInfoEXT debugCreateInfo;
        if (enableValidationLayers)
        {
            // 指定要捕获的消息严重级别：Verbose（详细信息）、Warning（警告）、Error（错误）
            vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(
                vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
                vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
                vk::DebugUtilsMessageSeverityFlagBitsEXT::eError);

            // 指定要捕获的消息类型：General（通用）、Performance（性能）、Validation（验证）
            vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(
                vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
                vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
                vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation);

            // 创建调试信使的创建信息结构体
            debugCreateInfo = vk::DebugUtilsMessengerCreateInfoEXT{
                {},
                severityFlags,
                messageTypeFlags,
                &debugCallback
            };
        }

        vk::InstanceCreateInfo createInfo(
#ifdef __APPLE__
            static_cast<vk::InstanceCreateFlags>(VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR),
#else
            {},
#endif
            &appInfo,
            static_cast<uint32_t>(requiredLayers.size()),
            requiredLayers.data(),
            static_cast<uint32_t>(requiredExtensions.size()),
            requiredExtensions.data());

        // 如果启用了验证层，将调试信使创建信息链接到实例创建信息的pNext链中
        if (enableValidationLayers)
        {
            createInfo.setPNext(&debugCreateInfo);
        }

        instance = vk::raii::Instance(context, createInfo);
    }
    // 设置调试信使：用于捕获并打印 Vulkan 验证层的调试信息
    void setupDebugMessenger()
    {
        // 如果未启用验证层，直接返回，无需创建调试信使
        if (!enableValidationLayers)
            return;

        // 指定要捕获的消息严重级别：Verbose（详细信息）、Warning（警告）、Error（错误）
        vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(
            vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
            vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
            vk::DebugUtilsMessageSeverityFlagBitsEXT::eError);

        // 指定要捕获的消息类型：General（通用）、Performance（性能）、Validation（验证）
        vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(
            vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
            vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
            vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation);

        // 创建调试信使的创建信息结构体
        // 第一个参数 {} 是默认的 vk::StructureChain 空初始化，其余依次填入严重级别、消息类型、回调函数指针
        vk::DebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfoEXT{
            {},
            severityFlags,
            messageTypeFlags,
            &debugCallback
        };

        // 利用已创建的 Vulkan 实例创建调试信使对象，并赋值给成员变量 debugMessenger
        debugMessenger = instance.createDebugUtilsMessengerEXT(debugUtilsMessengerCreateInfoEXT);
    }

    void pickPhysicalDevice(){
        // 枚举物理设备
        auto devices =instance.enumeratePhysicalDevices();
        const auto devIter = std::ranges::find_if(
          devices,
          [&]( auto const & device )
          {
            // 检查物理设备是否支持Vulkan 1.3 API版本
            bool supportsVulkan1_3 = device.getProperties().apiVersion >= VK_API_VERSION_1_3;

            // 检查物理设备是否支持图形操作的队列家族
            auto queueFamilies = device.getQueueFamilyProperties();
            bool supportsGraphics =
              std::ranges::any_of( queueFamilies, []( auto const & qfp ) { return !!( qfp.queueFlags & vk::QueueFlagBits::eGraphics ); } );

            // 检查物理设备是否支持所有需要的设备扩展
            auto availableDeviceExtensions = device.enumerateDeviceExtensionProperties();
            bool supportsAllRequiredExtensions =
              std::ranges::all_of( requiredDeviceExtension,
                                   [&availableDeviceExtensions]( auto const & requiredDeviceExtension )
                                   {
                                     return std::ranges::any_of( availableDeviceExtensions,
                                                                 [requiredDeviceExtension]( auto const & availableDeviceExtension )
                                                                 { return strcmp( availableDeviceExtension.extensionName, requiredDeviceExtension ) == 0; } );
                                   } );

            auto features = device.template getFeatures2<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan13Features, vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
            bool supportsRequiredFeatures = features.template get<vk::PhysicalDeviceVulkan13Features>().dynamicRendering &&
                                            features.template get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>().extendedDynamicState;

            return supportsVulkan1_3 && supportsGraphics && supportsAllRequiredExtensions && supportsRequiredFeatures;
          } );
        if ( devIter != devices.end() )
        {
            physicalDevice = *devIter;
        }
        else
        {
            throw std::runtime_error( "failed to find a suitable GPU!" );
        }

    }
    // 调试回调函数：被 Vulkan 验证层调用，用于输出调试信息
    // VKAPI_ATTR 和 VKAPI_CALL 确保使用 Vulkan 所需的调用约定
    static VKAPI_ATTR vk::Bool32 VKAPI_CALL debugCallback(
        vk::DebugUtilsMessageSeverityFlagBitsEXT severity, // 消息严重级别
        vk::DebugUtilsMessageTypeFlagsEXT type,            // 消息类型
        const vk::DebugUtilsMessengerCallbackDataEXT *pCallbackData, // 包含详细消息内容的回调数据
        void *                                               // 用户自定义数据指针（此处未使用）
    )
    {
        // 仅当消息为错误或警告时才打印，避免冗余输出
        //if (severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eError ||
        //    severity == vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning)
        //{
            // 输出消息类型与具体信息到标准错误流
            std::cerr << "validation layer: type " << to_string(type)
                      << " msg: " << pCallbackData->pMessage << std::endl;
        //}

        // 返回 vk::False 表示该消息未被应用层“处理”，Vulkan 将继续传递该消息
        return vk::False;
    }
    std::vector<const char *> getRequiredExtensions()
    {
        uint32_t glfwExtensionCount = 0;
        auto glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

        std::vector extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
        if (enableValidationLayers)
        {
            extensions.push_back(vk::EXTDebugUtilsExtensionName);
        }

        return extensions;
    }

    void createLogicalDevice() {
        // 获取物理设备支持的队列家族属性
        std::vector<vk::QueueFamilyProperties> queueFamilyProperties = physicalDevice.getQueueFamilyProperties();

        // get the first index into queueFamilyProperties which supports both graphics and present
        uint32_t graphicsIndex = ~0;
        for (uint32_t qfpIndex = 0; qfpIndex < queueFamilyProperties.size(); qfpIndex++)
        {
          if ((queueFamilyProperties[qfpIndex].queueFlags & vk::QueueFlagBits::eGraphics) &&
              physicalDevice.getSurfaceSupportKHR(qfpIndex, *surface))
          {
            // found a queue family that supports both graphics and present
            graphicsIndex = qfpIndex;
            break;
          }
        }
        if (graphicsIndex == ~0)
        {
          throw std::runtime_error("Could not find a queue for graphics and present -> terminating");
        }
        
        // query for Vulkan 1.3 features
        vk::PhysicalDeviceFeatures2 feature2;
        vk::PhysicalDeviceVulkan13Features feature13;
        feature13.dynamicRendering = true;
        vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT featureEXT;
        featureEXT.extendedDynamicState = true;
        vk::StructureChain<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan13Features, vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT> featureChain = {
            feature2,
            feature13,
            featureEXT
        };

        // create a Device
        float                     queuePriority = 0.0f;
        vk::DeviceQueueCreateInfo deviceQueueCreateInfo{{},graphicsIndex,1,&queuePriority };
        vk::DeviceCreateInfo      deviceCreateInfo{};
        deviceCreateInfo.pNext = &featureChain.get<vk::PhysicalDeviceFeatures2>();
        deviceCreateInfo.queueCreateInfoCount = 1;
        deviceCreateInfo.pQueueCreateInfos = &deviceQueueCreateInfo;
        deviceCreateInfo.enabledExtensionCount = static_cast<uint32_t>(requiredDeviceExtension.size());
        deviceCreateInfo.ppEnabledExtensionNames = requiredDeviceExtension.data();

        device = vk::raii::Device(physicalDevice, deviceCreateInfo);
        graphicsQueue = vk::raii::Queue( device, graphicsIndex, 0 );
    }

    void createSurface()
    {
        VkSurfaceKHR _surface;
        if(glfwCreateWindowSurface(*instance, window, nullptr, &_surface) != VK_SUCCESS)
        {
            throw std::runtime_error("Failed to create window surface!");
        }
        surface = vk::raii::SurfaceKHR(instance, _surface);
    }
};
int main()
{
    try
    {
        HelloTriangleApplication app;
        app.run();
    }
    catch (const std::exception &e)
    {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}